package com.zhulong.saas.cloud.gateway.config;

import com.zhulong.saas.cloud.gateway.adapt.UserAdapt;
import com.zhulong.saas.cloud.gateway.adapt.UserAdaptImpl;
import com.zhulong.saas.cloud.gateway.oauth2.BearerTokenServerAuthenticationConverter;
import com.zhulong.saas.cloud.gateway.oauth2.Oauth2TokenAuthenticationManager;
import com.zhulong.saas.cloud.gateway.security.AuthorizeExchangeSpecCustomizer;
import com.zhulong.saas.cloud.gateway.security.SubjectBusTypeEnum;
import com.zhulong.saas.cloud.gateway.security.TenantSubjectReactiveAuthorizationManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.security.oauth2.resource.UserInfoTokenServices;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.security.authentication.ReactiveAuthenticationManager;
import org.springframework.security.authorization.AuthorizationDecision;
import org.springframework.security.authorization.ReactiveAuthorizationManager;
import org.springframework.security.config.web.server.SecurityWebFiltersOrder;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.web.server.SecurityWebFilterChain;
import org.springframework.security.web.server.authentication.AuthenticationWebFilter;
import org.springframework.security.web.server.authentication.HttpStatusServerEntryPoint;
import org.springframework.security.web.server.authentication.ServerAuthenticationConverter;
import org.springframework.security.web.server.authentication.ServerAuthenticationEntryPointFailureHandler;
import org.springframework.security.web.server.authorization.AuthorizationContext;
import reactor.core.publisher.Mono;

import java.util.List;


@Configuration
public class SecurityConfig {

    @Autowired
    private AuthConfigPropertiesBean authConfigPropertiesBean;

    @Value("${uaa.userInfoUrl}")
    private String uaaUrl;

    @Value("${uaa.clientId}")
    private String clientId;

    @Autowired
    private List<AuthorizeExchangeSpecCustomizer> exchangeSpecCustomizers;

    @Bean
    public Oauth2TokenAuthenticationManager oauth2TokenAuthenticationManager() {
        UserInfoTokenServices tokenServices = new UserInfoTokenServices(uaaUrl, clientId);
        Oauth2TokenAuthenticationManager manager = new Oauth2TokenAuthenticationManager(tokenServices);
        return manager;
    }

    @Bean
    public UserAdapt userAdapt() {
        return new UserAdaptImpl();
    }

    @Bean
    SecurityWebFilterChain webFluxSecurityFilterChain(ServerHttpSecurity http) throws Exception {

        //token管理器
        ReactiveAuthenticationManager tokenAuthenticationManager = oauth2TokenAuthenticationManager();
        //认证过滤器
        ServerAuthenticationConverter converter = new BearerTokenServerAuthenticationConverter();
        AuthenticationWebFilter authenticationWebFilter = new AuthenticationWebFilter(tokenAuthenticationManager);
        authenticationWebFilter.setAuthenticationFailureHandler(new ServerAuthenticationEntryPointFailureHandler(new HttpStatusServerEntryPoint(HttpStatus.UNAUTHORIZED)));
        authenticationWebFilter.setServerAuthenticationConverter(converter);
        ServerHttpSecurity.AuthorizeExchangeSpec exchangeSpec = http.httpBasic().disable()
                .csrf().disable()
                // 跨域过滤器
//                .addFilterAt(corsFilter(), SecurityWebFiltersOrder.CORS)
                //oauth2认证过滤器
                .addFilterAt(authenticationWebFilter, SecurityWebFiltersOrder.AUTHENTICATION)
                .authorizeExchange()
                .pathMatchers(HttpMethod.OPTIONS).permitAll()
                .pathMatchers("/swagger-ui/**", "/swagger-resources/**", "/**/v3/api-docs","/doc.html").permitAll()
                .pathMatchers("/cache/**").permitAll()
                .pathMatchers(authConfigPropertiesBean.getNoAuthUrls().toArray(new String[]{})).permitAll()
                .pathMatchers("/**/internal/**").permitAll();
        //针对各个系统的调用  单独进行配置
        exchangeSpecCustomizers.forEach(c -> c.customize(exchangeSpec));

        exchangeSpec.anyExchange().authenticated();
        return http.build();
    }
}
